#pragma once
#include "../common/message.hpp"
#include "../common/net.hpp"
#include "requestor.hpp"
#include <future>

namespace myrpc{
    namespace client{
        class RpcCaller {
        public:
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonRspFuture = std::future<Json::Value>;
            using JsonRspCallBack = std::function<void(const Json::Value &)>;
            RpcCaller(const Requestor::ptr &requestor)
                : _requestor(requestor)
            {}

            // 同步调用 等待获取到响应结果后才返回
            bool call(const BaseConnection::ptr &conn, const std::string &method, 
                    const Json::Value &params, Json::Value &result){
                // 1.组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setMethod(method);
                req_msg->setMsgId(UuId::uuId());
                req_msg->setMsgType(MsgType::REQ_RPC);
                req_msg->setParameters(params);
                BaseMessage::ptr msg;
                // 2.发送请求
                client_logger->DEBUG("发送同步 RPC 请求 -> 方法: '%s', ID: %s", method.c_str(), req_msg->getMsgId().c_str());
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), msg);
                if (ret == false){
                    client_logger->ERROR("发送同步 RPC 请求失败!");
                    return false;   
                }
                // 3. 获取最终结果
                client_logger->DEBUG("收到同步 RPC 响应 -> ID: %s", msg->getMsgId().c_str());
                auto rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (rsp_msg.get() == nullptr){
                    client_logger->ERROR("RPC 响应类型转换失败!");
                    return false;
                }  
                if (rsp_msg->getRCode() != RCode::RCODE_OK){
                    client_logger->ERROR("RPC 请求出错 -> ID: %s, 原因: %s", msg->getMsgId().c_str(), errReason(rsp_msg->getRCode()).c_str());
                    return false;
                }
                result = rsp_msg->getResult();
                return true;
            }

            // 异步调用 立即返回 收到响应消息后立即回调处理 并将结果存放到promise对象中
            bool call(const BaseConnection::ptr &conn, const std::string &method, 
                    const Json::Value &params, JsonRspFuture &result){
                // 组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setMethod(method);
                req_msg->setMsgId(UuId::uuId());
                req_msg->setMsgType(MsgType::REQ_RPC);
                req_msg->setParameters(params);
                // 获取future关联对象以及设置回调处理
                auto rsp_prom = std::make_shared<std::promise<Json::Value>>();
                result = rsp_prom->get_future();
                Requestor::ReqCallBack cb = std::bind(&RpcCaller::callBack1, this, rsp_prom, std::placeholders::_1);
                // 发送请求
                client_logger->DEBUG("发送异步 RPC 请求 -> 方法: '%s', ID: %s", method.c_str(), req_msg->getMsgId().c_str());
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), cb);
                if (ret == false){
                    client_logger->ERROR("发送异步 RPC 请求失败!");
                    return false;
                }
                return true;
            }

            // 回调调用 立即返回 收到响应消息后立即回调处理 然后执行用户设置的回调处理
            bool call(const BaseConnection::ptr &conn, const std::string &method, 
                const Json::Value &params, const JsonRspCallBack &user_cb){
                // 组织请求
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setMethod(method);
                req_msg->setMsgId(UuId::uuId());
                req_msg->setMsgType(MsgType::REQ_RPC);
                req_msg->setParameters(params);
                // 设置回调处理函数
                Requestor::ReqCallBack cb = std::bind(&RpcCaller::callBack2, this, user_cb, std::placeholders::_1);
                // 发送请求
                client_logger->DEBUG("发送回调 RPC 请求 -> 方法: '%s', ID: %s", method.c_str(), req_msg->getMsgId().c_str());
                bool ret = _requestor->send(conn, std::dynamic_pointer_cast<BaseMessage>(req_msg), cb);
                if (ret == false){
                    client_logger->ERROR("发送回调 RPC 请求失败!");
                    return false;
                }
                return true;
            }

        private:
            // 异步调用的回调处理函数
            void callBack1(std::shared_ptr<std::promise<Json::Value>> rsp_prom, const BaseMessage::ptr &msg){
                client_logger->DEBUG("开始处理异步 RPC 响应 -> ID: %s", msg->getMsgId().c_str());
                auto rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (rsp_msg.get() == nullptr){
                    client_logger->ERROR("RPC 响应类型转换失败!");
                    return;
                }
                if (rsp_msg->getRCode() != RCode::RCODE_OK){
                    client_logger->ERROR("RPC 请求出错 -> ID: %s, 原因: %s", msg->getMsgId().c_str(), errReason(rsp_msg->getRCode()).c_str());
                    return;
                }
                rsp_prom->set_value(rsp_msg->getResult());
                client_logger->DEBUG("异步 RPC 响应处理成功 -> ID: %s, 已设置 Promise", msg->getMsgId().c_str());
            } 
            // 回调调用的回调处理函数
            void callBack2(const JsonRspCallBack &user_cb, const BaseMessage::ptr &msg){
                client_logger->DEBUG("开始处理回调 RPC 响应 -> ID: %s", msg->getMsgId().c_str());
                auto rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (rsp_msg.get() == nullptr){
                    client_logger->ERROR("RPC 响应类型转换失败!");
                    return;
                }
                if (rsp_msg->getRCode() != RCode::RCODE_OK){
                    client_logger->ERROR("RPC 请求出错 -> ID: %s, 原因: %s", msg->getMsgId().c_str(), errReason(rsp_msg->getRCode()).c_str());
                    return;
                }
                user_cb(rsp_msg->getResult());
                client_logger->DEBUG("回调 RPC 响应处理成功 -> ID: %s, 已执行用户回调", msg->getMsgId().c_str());
            }

        private:
            Requestor::ptr _requestor;
        };
    }
}